import { CanvasBase } from "./canvasBase";
import { getColor } from "./color";
import {
    LINE_BREAKS,
    LINE_BREAKS_RENDER,
    HOVERED_RECT_COLOR,
    SELECTED_RECT_COLOR,
    DEFAULT_LINE_COLOR,
    DEFAULT_FONT_FAMILY,
    DEFAULT_FONT_SIZE,
} from "./config";
import {
    ARROW_DOWN,
    ARROW_KEY_SET,
    ARROW_LEFT,
    ARROW_RIGHT,
    ARROW_UP,
    BACKSPACE,
    ENTER,
    ESCAPE,
    HIDE_CURSOR_COLOR,
    IBaseChar,
    IChar,
    ICursor,
    ICursorSelectPos,
    ILineChars,
    IPosition,
    ISelectZmind,
    SHOW_CURSOR_COLOR,
    TArrowKey,
} from "./type";
import {
    getXY,
    gFont,
    UUID,
} from "./utils";

export class Zmind extends CanvasBase {
    // 输入框
    private _input: HTMLInputElement = document.createElement('input');
    // 光标
    private _cursor: ICursor = {
        x: 100,
        y: 100,
        w: 2, // 光标宽度固定为2px
        h: 0, // 光标高度根据左右节点的最大高度计算【大于0处于编辑状态】
        color: SHOW_CURSOR_COLOR, // 光标颜色 切换为红黑
        interval: 300, // 光标闪烁的时间间隔
        setIntervalNum: 0,
        startIndex: 0,
        startLocation: 'mid',
        renderStartIndex: 0,
        endIndex: 0,
        endLocation: 'mid',
        renderEndIndex: 0,
    };
    private _selectEleId: string = ''; // 当前选中的元素 不可重叠
    private _hoverEleId: string = ''; // 悬停的元素ID 不可重叠
    private _prevMouseMovePos: IPosition = { x: 0, y: 0 }; // 上次鼠标移动位置
    // 若有多个zmind，可以选择控制其中的某个
    private _selectZmind: ISelectZmind; // 选择的zmind 和 _zmindIndex 控制当前选择可以操作的画布
    private _zmindIndex: number; // zmind的索引；鼠标进入切换当前 zmind 的索引
    private _pressInfo = {
        state: false,
    };

    /**
     * 实例化
     * @param root 依附节点
     * @param width 设置节点宽度
     * @param height 设置节点高度
     * @param selectZmind 用于分屏操作，多个 zmind 时通过切换 zmindIndex 控制当前选择的 zmind；多个实例要用同一个 selectZmind
     * @param zmindIndex zmind 的唯一索引，用于切换当前选择的 zmind
     */
    constructor(root: HTMLElement, width: number, height: number, selectZmind: ISelectZmind, zmindIndex: number) {
        super(root, width, height);
        this._selectZmind = selectZmind;
        this._zmindIndex = zmindIndex;

        this.initEvent();
        this.initInput(root);
        this.initFirstData(); // 初始化第一个数据
    }
    /**
     * 输入框初始化
     * @param root 
     */
    private initInput(root: HTMLElement) {
        root.appendChild(this._input);
        this._input.style.position = 'absolute';
        this._input.style.zIndex = '-1';
        this._input.style.top = '0';
        this._input.style.left = '0';
        this._input.style.right = '0';
        this._input.style.border = 'none';
        this._input.style.outline = 'none';
        this._input.style.backgroundColor = 'transparent';
        this._input.style.caretColor = 'transparent'; // 初始透明
        this._input.style.userSelect = 'none'; // 禁止选中
        this._input.style.textDecoration = '4px solid underline';
        this._input.style.textShadow = 'rgb(5 5 5) -2px -2px, rgb(5 5 5) -2px -2px 2px, rgb(9 9 9) 2px 2px';
        this._input.style.color = '#ffffff';
        this._input.style.fontSize = '20px';
        this._input.style.textUnderlineOffset = '10px';
        this._input.style.pointerEvents = 'none';
        this._input.addEventListener('input', (e: Event) => {
            const ev = e as InputEvent;
            if (ev.inputType !== 'insertText') { return; }
            const value = this._input.value;
            this.addChars(value);
            this._input.value = '';
        });
        this._input.addEventListener('compositionend', e => {
            const values = this._input.value;
            this.addChars(values);
            this._input.value = '';
        });
    }
    /**
     * 设置输入框位置
     */
    private setInputPos() {
        const { x, y, h } = this._cursor;
        this._input.style.zIndex = '1000'; // 确保输入框在最上层
        this._input.style.display = 'inline'; // 显示输入框
        this._input.style.left = String(x) + 'px';
        this._input.style.top = String(y + h) + 'px';
    }
    /**
     * 隐藏输入框
     */
    private hideInput() {
        this._input.blur(); // 失去焦点
        this._input.style.zIndex = '-1'; // 隐藏输入框
        this._input.style.display = 'none'; // 隐藏输入框
    }
    /**
     * 添加字符
     * @param chars 
     * @returns 
     */
    private addChars(chars: string) {
        if (!this._selectEleId || !this._cursor.h) { return; }
        const ele = this.getElementById(this._selectEleId);
        if (!ele) { return; }
        if (!ele.baseChars) {
            ele.baseChars = [];
        }
        const newAddChars: IBaseChar[] = [];
        if (chars === LINE_BREAKS) {
            newAddChars.push({
                c: LINE_BREAKS,
                fontSize: DEFAULT_FONT_SIZE,
                fontFamily: DEFAULT_FONT_FAMILY,
                color: '',
            });
        } else {
            newAddChars.push(...chars.split('').map(c => {
                return {
                    c,
                    fontSize: DEFAULT_FONT_SIZE,
                    fontFamily: DEFAULT_FONT_FAMILY,
                    color: '',
                };
            }));
        }
        ele.baseChars.splice(this._cursor.startIndex, 0, ...newAddChars); // 在光标位置插入新字符
        this._cursor.startIndex += newAddChars.length; // 更新光标位置

        this.baseChars2LineChars(this._selectEleId); // 将整个字符转换为行字符
        this.calculatePos(); // 计算位置
        this.calculateVisibleLinesPos(); // 计算可见线的位置
        this.moveEleVisible(this._selectEleId);
        this.showCursor(); // 显示光标
        this.render();
    }
    /**
     * 删除字符
     * @returns 
     */
    private delChars() {
        if (!this._selectEleId) { return; }
        const ele = this.getElementById(this._selectEleId);
        if (!ele || !ele.baseChars || ele.baseChars.length === 0) { return; }
        if (this._cursor.startIndex > 0) {
            this._cursor.startIndex--; // 光标向左移动
            ele.baseChars.splice(this._cursor.startIndex, 1); // 删除光标前的字符

            this.baseChars2LineChars(this._selectEleId); // 更新行字符
            this.calculatePos(); // 计算位置
            this.moveElesCalculateVisible(0, 0);
            this.showCursor(); // 重新绘制光标
            this.calculateVisibleLinesPos(); // 计算可见线的位置
            this.render();
        }
    }
    /**
     * 初始化第一个节点信息
     */
    private initFirstData() {
        const id = UUID();
        const { h } = this.getHeightByFont(gFont());
        const { bg, color } = getColor();
        const dataHeight = h + this.TB_PADDING * 2;
        const defaultRectMinWidth = this.DEFAULT_RECT_MIN_WIDTH;
        this.addData(id, {
            id,
            w: defaultRectMinWidth,
            h: dataHeight,
            x: (this.canvasWidth - defaultRectMinWidth) / 2,
            y: (this.canvasHeight - dataHeight) / 2,
            baseChars: [],
            lineChars: [],
            parentId: '',
            bg,
            color,
            children: {
                ids: [],
                mh: 0,
                mw: 0,
            },
        });
        this.render();
    }
    /**
     * 事件入口
     */
    private initEvent() {
        // 右键
        this.addEventListener('contextmenu', e => {
            e.preventDefault();
            console.log(this.dataObject);
        });
        // 双击编辑
        this.addEventListener('dblclick', (e => {
            const { x, y } = getXY(e);
            const ele = this.getElementByXY(x, y);
            if (ele) {
                this._selectEleId = ele.id;
                const moveCursorPos = this.moveCursorByPos(x, y);
                const startIndex = moveCursorPos.index;
                this._cursor.startIndex = startIndex > -1 ? startIndex : ele.baseChars.length;
                this._cursor.startLocation = moveCursorPos.location;
                this.showCursor();
                this._input.focus();
            }
        }));
        this.addEventListener('mousedown', e => {
            this._pressInfo.state = true;
            const { x, y } = getXY(e);
            const ele = this.getElementByXY(x, y);
            const prevSelectEleId = this._selectEleId || ''; // 记录之前的选中元素ID
            if (!ele) {
                if (this._cursor.h) {
                    this.hideCursor();
                }
                this._selectEleId = '';
            } else {
                this._cursor.renderStartIndex = -1;
                this._cursor.renderEndIndex = -1;
                if (ele.id !== this._selectEleId) {
                    this.hideCursor();
                    this._selectEleId = ele.id;
                } else if (this._cursor.h) {
                    const prevStartIndex = this._cursor.startIndex;
                    const moveCursorPos = this.moveCursorByPos(x, y);
                    this._cursor.startIndex = moveCursorPos.index;
                    this._cursor.startLocation = moveCursorPos.location;
                    if (prevStartIndex !== this._cursor.startIndex) {
                        this.showCursor();
                    }
                }
            }
            if (prevSelectEleId !== this._selectEleId) {
                this.render();
            }
        });
        this.addEventListener('mouseup', e => {
            this._pressInfo.state = false;
            const { x, y } = getXY(e);
            const ele = this.getElementByXY(x, y);
            if (ele && this._cursor.h) {
                this._input.focus(); // 保持输入框焦点
            }
        });
        this.addEventListener('mousemove', e => {
            const { x, y } = getXY(e);
            this._prevMouseMovePos = { x, y }; // 记录上次鼠标位置
            const prevHoverEleId = this._hoverEleId;
            this.setHoverElementId(x, y); // 设置悬停元素ID
            const cursorTextSelect = this.calculateCursorTextSelect(x, y);
            if (cursorTextSelect || this._hoverEleId !== prevHoverEleId) {
                this.render();
            }
        });
        this.addEventListener('mouseenter', e => {
            this._selectZmind.index = this._zmindIndex; // 设置当前zmind的索引
        });
        this.addEventListener('wheel', e => {
            e.preventDefault();
            if (this._cursor.h) { return; } // 文字编辑状态下，不可滚动
            const { deltaX, deltaY, ctrlKey } = e;
            const { x, y } = getXY(e);
            if (ctrlKey) {
                const prevZoom = this.zoomInOut;
                if (deltaY < 0) {
                    this.zoomFontSize++;
                } else if (this.zoomFontSize > 1) {
                    this.zoomFontSize--;
                } else {
                    return;
                }
                const currZoom = this.zoomInOut;
                const currOffsetX = x / prevZoom - x / currZoom;
                const currOffsetY = y / prevZoom - y / currZoom;
                this.zoomDatas(prevZoom, currZoom, currOffsetX, currOffsetY); // 缩放数据
                this.moveElesCalculateVisible(0, 0); // 可视判断
            } else {
                this.moveElesCalculateVisible(-deltaX, -deltaY); // 移动位置
            }
            this.setHoverElementId(x, y);
            this.calculateVisibleLinesPos();
            this.render();
        });
        window.addEventListener('keydown', e => {
            if (this._selectZmind.index !== this._zmindIndex) { return; }
            const { shiftKey, key } = e;

            if (this._cursor.h) { // 光标存在，编辑状态
                if (key === ENTER && !this._input.value) { // 编辑状态下添加换行符
                    if (shiftKey) {
                        this.addChars(LINE_BREAKS);
                    } else {
                        this.hideCursor(); // 隐藏光标
                        this.hideInput();
                    }
                } else if (key === BACKSPACE && !this._input.value) {  // 删除光标前的字符
                    this.delChars();
                } else if (ARROW_KEY_SET.has(key)) {
                    this.moveCursorByArraw(key as TArrowKey);
                } else if (key === ESCAPE) {
                    this.hideCursor(); // 隐藏光标
                    this.hideInput(); // 隐藏输入框
                }
            } else { // 非编辑状态
                // 通过方向键添加节点
                if (shiftKey && ARROW_KEY_SET.has(key)) {
                    const rectHeight = this.getHeightByFont(gFont(this.zoomFontSize)).h + this.TB_PADDING * 2; // 获取矩形高度
                    const uId = this.addNodeByDirection(this._selectEleId, key as TArrowKey, rectHeight);
                    if (uId) {
                        this.calculatePos();
                        this.calculateVisibleLinesPos(); // 计算可见线的位置
                        this._selectEleId = uId; // 更新选中元素ID
                        this.moveEleVisible(this._selectEleId);
                        this.setHoverElementId(this._prevMouseMovePos.x, this._prevMouseMovePos.y); // 悬停元素
                        this.render();
                    }
                } else if (key === ESCAPE) {
                    this._selectEleId = ''; // 不在选择节点
                    this.render();
                } else if (ARROW_KEY_SET.has(key)) {
                    // 移动选择状态
                    this.changeSelectEleIdByArrow(key as TArrowKey);
                    this._selectEleId = this._selectEleId || this.firstId; // 如果没有选中元素，则选择第一个元素
                    this.moveEleVisible(this._selectEleId);
                    this.render();
                } else if (key === ENTER) {
                    // 进入编辑状态
                    if (this._selectEleId) {
                        const ele = this.getElementById(this._selectEleId);
                        if (ele) {
                            this._cursor.startIndex = ele.baseChars.length;
                            this.showCursor();
                            this._input.focus();
                        }
                    }
                } else if (key === BACKSPACE) {
                    // 删除选中元素
                    if (this._selectEleId) {
                        const ele = this.getElementById(this._selectEleId);
                        if (!ele || ele.id === this.firstId || !ele.parentId) { return; } // 不允许删除第一个元素
                        const selectIdAfterDel = this.delData(this._selectEleId); // 删除选中元素及其子元素
                        if (selectIdAfterDel) {
                            this._selectEleId = selectIdAfterDel;
                        }
                        this.calculatePos(); // 计算位置
                        this.moveElesCalculateVisible(0, 0);
                        this.calculateVisibleLinesPos(); // 计算可见线的位置
                        this.moveEleVisible(this._selectEleId);
                        this.render();
                    }
                }
            }
        });
    }
    /**
     * 调整画布宽高，对外暴露
     * @param width 
     * @param height 
     */
    setZmindWidthHeight(width: number, height: number) {
        this.setWidthHeight(width, height);
        this.moveElesCalculateVisible(0, 0);
        this.calculateVisibleLinesPos(); // 计算可见线的位置
        this.render();
    }
    /**
     * 根据箭头移动光标索引位置
     * @param arrow 
     * @returns 
     */
    private moveCursorByArraw(arrow: TArrowKey) {
        if (!this._selectEleId) { return; }
        const prevStartIndex = this._cursor.startIndex; // 记录光标起始位置
        const selectItem = this.getElementById(this._selectEleId);
        if (!selectItem) { return; }
        const { baseChars, lineChars } = selectItem;
        if (arrow === ARROW_LEFT || arrow === ARROW_RIGHT) {
            this._cursor.startIndex += (arrow === ARROW_RIGHT ? 1 : -1); // 光标向左或向右移动
            if (this._cursor.startIndex < 0) {
                this._cursor.startIndex = 0; // 光标不能小于0
            } else if (this._cursor.startIndex >= baseChars.length) {
                this._cursor.startIndex = baseChars.length; // 光标不能超过字符长度
            }
        } else if (arrow === ARROW_DOWN || arrow === ARROW_UP) {
            let startIndex = this._cursor.startIndex;
            let currentLineIndex = 0; // 当前行索引
            let currentX = 0;
            let goalIndex = 0; // 目标行索引
            for (let i = 0; i < lineChars.length; i++) {
                const line = lineChars[i];
                if (startIndex < line.chars.length) {
                    currentLineIndex = i; // 找到当前行索引
                    const char = line.chars[startIndex];
                    currentX = char ? char.x : line.x; // 光标在当前行的字符位置
                    break;
                } else if (startIndex === line.chars.length) {
                    const lastChar = line.chars[line.chars.length - 1];
                    if (lastChar.c === LINE_BREAKS_RENDER) { // 换行符
                        currentLineIndex = i + 1; // 光标在下一行的起始位置
                        currentX = line.x;
                        goalIndex += line.chars.length;
                    } else {
                        currentLineIndex = i;
                        currentX = line.x + line.w; // 当前行的末尾x坐标
                    }
                    break;
                }
                startIndex -= line.chars.length;
                goalIndex += line.chars.length;
            }
            if (arrow === ARROW_UP && currentLineIndex > 0) {
                const prevLine = lineChars[currentLineIndex - 1];
                if (prevLine) {
                    goalIndex -= prevLine.chars.length; // 向上移动一行
                    for (let i = 0; i < prevLine.chars.length - 1; i++) {
                        const char = prevLine.chars[i];
                        if (char.x <= currentX && char.x + char.w > currentX) {
                            break;
                        }
                        goalIndex++; // 找到当前行的字符位置
                    }
                }
                this._cursor.startIndex = goalIndex; // 更新光标位置
            } else if (arrow === ARROW_DOWN && currentLineIndex < lineChars.length - 1) {
                const nextLine = lineChars[currentLineIndex + 1];
                if (nextLine) {
                    goalIndex += lineChars[currentLineIndex].chars.length; // 向下移动一行
                    for (let i = 0; i < nextLine.chars.length; i++) {
                        const char = nextLine.chars[i];
                        if (char.c === LINE_BREAKS) {
                            break;
                        } else {
                            if (char.x <= currentX && char.x + char.w > currentX) {
                                break;
                            }
                            goalIndex++; // 找到当前行的字符位置
                        }
                    }
                }
                this._cursor.startIndex = goalIndex; // 更新光标位置
            }
        }
        // 若有变化才会重新绘制光标
        if (prevStartIndex !== this._cursor.startIndex) {
            this.showCursor(); // 重新绘制光标
        }
    }
    /**
     * 根据位置移动光标
     * @param x 
     * @param y 
     */
    private moveCursorByPos(x: number, y: number): ICursorSelectPos {
        const result: ICursorSelectPos = { index: 0, location: '' };
        if (!this._selectEleId) {
            result.index = -2;
            return result;
        }
        const selectItem = this.getElementById(this._selectEleId);
        if (!selectItem) {
            result.index = -3;
            return result;
        }
        const { lineChars } = selectItem;
        for (let i = 0; i < lineChars.length; i++) {
            const line = lineChars[i];
            const len = line.chars.length;
            if (y >= line.y && y < line.y + line.h) {
                for (let j = 0; j < line.chars.length; j++) {
                    const lineChar = line.chars[j];
                    if (j === 0) {
                        if (x < lineChar.x) {
                            result.location = 'after';
                        } else if (x > lineChar.x) {
                            result.location = 'prev';
                        } else {
                            result.location = 'mid';
                        }
                        if (x < lineChar.x + lineChar.w / 2) {
                            break;
                        }
                    } else if (j < line.chars.length - 1) {
                        const prevLineChar = line.chars[j - 1];
                        if (x < lineChar.x) {
                            result.location = 'after';
                        } else if (x > lineChar.x) {
                            result.location = 'prev';
                        } else {
                            result.location = 'mid';
                        }
                        if (x >= lineChar.x - prevLineChar.w / 2 && x < lineChar.x + lineChar.w / 2) {
                            break;
                        }
                    } else if (j === line.chars.length - 1) { // 留着，逻辑结构比较清楚
                        if (x < lineChar.x) {
                            result.location = 'after';
                        } else if (x > lineChar.x) {
                            result.location = 'prev';
                        } else {
                            result.location = 'mid';
                        }
                        if (lineChar.c !== LINE_BREAKS_RENDER) {
                            if (x >= lineChar.x + lineChar.w / 2) {
                                result.index++;
                            }
                        }
                        break;
                    }
                    result.index++;
                }
                return result;
            } else {
                result.index += len;
            }
        }
        result.index = -1;
        return result;
    }
    // 渲染页面
    private render() {
        this.clear();
        const visibleElements = this.visibleElements();
        const selectedRectPadding = this.SELECTED_RECT_PADDING;
        for (const item of visibleElements) {
            const { x, y, w, h, id, bg, color } = item;
            // 选中绘制或hover
            if (id === this._selectEleId || id === this._hoverEleId) {
                const doublePadding = 2 * selectedRectPadding;
                const shX = x - selectedRectPadding;
                const shY = y - selectedRectPadding;
                const shW = w + doublePadding;
                const shH = h + doublePadding;
                const shStrokeStyle = id === this._selectEleId ? SELECTED_RECT_COLOR : HOVERED_RECT_COLOR;
                const shLineWidth = 2;
                this.drawRoundRect(shX, shY, shW, shH, {
                    strokeStyle: shStrokeStyle,
                    lineWidth: shLineWidth,
                });
            }
            // 绘制背景色
            this.drawRoundRect(x, y, w, h, {
                fillStyle: bg,
            });

            // 绘制矩形
            // this.drawRoundRect(x, y, w, h, {
            //     strokeStyle: this._hoverEleId === id ? HOVERED_RECT_COLOR : DEFAULT_RECT_COLOR,
            //     lineWidth: 2,
            // });
            // 绘制文本和矩形
            if (item.lineChars) {
                let index = 0;
                for (let i = 0; i < item.lineChars.length; i++) {
                    const lineChar = item.lineChars[i];
                    for (let j = 0; j < lineChar.chars.length; j++) {
                        const char = lineChar.chars[j];
                        // 绘制字符
                        this.drawText(char.c, char.x, char.y, {
                            font: gFont(char.fontSize, char.fontFamily),
                            fillStyle: char.color || color,
                        });
                        const { renderStartIndex, renderEndIndex } = this._cursor;
                        if (this._selectEleId === id && index >= renderStartIndex && index < renderEndIndex) {
                            // 绘制字符矩形
                            this.drawRect(char.x, char.ry, char.w, lineChar.h, {
                                strokeStyle: 'green',
                            });
                        }
                        index++;
                    }
                    // 绘制行矩形
                    // if (lineChar.chars.length === 0) {
                    //     this.drawRect(lineChar.x, lineChar.y, lineChar.w, lineChar.h, {
                    //         strokeStyle: 'blue',
                    //     });
                    // }
                }
            }
        }
        // 绘制链接线
        const visiableLines = Object.values(this.visiableLinesPosArray);
        for (const linePos of visiableLines) {
            if (linePos.length > 1) {
                const tLinePos: IPosition[] = [];
                linePos.forEach(t => {
                    tLinePos.push({ x: t.x, y: t.y });
                });
                this.drawLine(tLinePos, {
                    strokeStyle: DEFAULT_LINE_COLOR,
                    lineWidth: this.defaultLineWidth().defaultLineWidth,
                });
            }
        }
    }
    /**
     * 计算光标宽高位置并绘制
     * @returns 
     */
    private showCursor() {
        this.hideCursor(); // 先隐藏之前的光标
        // 计算光标的高度和位置
        if (!this._selectEleId) { return; }
        const selectEle = this.getElementById(this._selectEleId);
        if (!selectEle) { return; }
        const { x, y, lineChars, h, w } = selectEle;
        const lengthLineChars = lineChars.length;
        if (lengthLineChars === 0) {
            const { h: defaultHeight } = this.getHeightByFont(gFont());
            this._cursor.h = this.getZoomValue(defaultHeight); // 光标高度为换行符的高度
            // this._cursor.x = x + LR_PADDING; // 光标左对齐
            this._cursor.x = x + (w - this._cursor.w) / 2; // 光标水平居中
            this._cursor.y = y + (h - this._cursor.h) / 2; // 光标垂直居中
        } else {
            let startIndex = this._cursor.startIndex;
            for (let i = 0; i < lengthLineChars; i++) {
                const line = lineChars[i];
                // 判断是否在当前行
                if (startIndex <= line.chars.length) {
                    const char = line.chars[startIndex];
                    if (char) {
                        this._cursor.h = char.hAscent + char.hDescent; // 光标高度为当前字符的高度
                        this._cursor.y = char.y - char.hAscent; // 光标y坐标为字符的基线对齐
                        this._cursor.x = char.x - this._cursor.w / 2; // 光标在字符的右侧
                    } else { // 如果没有字符，则光标在行的末尾
                        if (i === lengthLineChars - 1) {
                            this._cursor.h = line.maxHAscent + line.maxHDescent; // 光标高度为当前行的最大高度
                            this._cursor.y = line.y;
                            this._cursor.x = line.x + line.w; // 光标在行的右侧
                        } else {
                            const nextLine = lineChars[i + 1];
                            this._cursor.h = nextLine.maxHAscent + nextLine.maxHDescent; // 光标高度为下一行的最大高度
                            this._cursor.y = nextLine.y; // 光标y坐标为下一行的起始y坐标
                            this._cursor.x = nextLine.x;
                        }
                    }
                    break;
                } else {
                    startIndex -= line.chars.length; // 减去当前行的字符长度，继续查找下一行
                }
            }
        }
        this._cursor.x;
        this._cursor.y;
        this._cursor.h;
        this._drawCursor();
        this.setInputPos(); // 设置输入框位置
        this._cursor.setIntervalNum = window.setInterval(() => {
            this._drawCursor();
        }, this._cursor.interval);
    }
    /**
     * 绘制光标，根据光标信息绘制
     */
    private _drawCursor() {
        const { x, y, w, h, color } = this._cursor;
        this._cursor.color = color === SHOW_CURSOR_COLOR ? HIDE_CURSOR_COLOR : SHOW_CURSOR_COLOR; // 切换颜色
        this.drawRoundRect(x, y, w, h, {
            fillStyle: this._cursor.color,
        });
    }
    /**
     * 隐藏光标，将光标高度设置为0
     */
    private hideCursor() {
        this._cursor.h = 0; // 重置光标高度
        clearInterval(this._cursor.setIntervalNum);
        this.render(); // 清除光标
    }
    /**
     * 生成行字符
     * @returns 
     */
    private generateLineChars(): ILineChars {
        const { h, hAscent, hDescent } = this.getHeightByFont(gFont(this.zoomFontSize));
        return { // 首行
            chars: [],
            w: 0, // 当前行的宽度 累加
            h, // 当前行的高度
            x: 0, // 当前行的起始x坐标
            y: 0, // 当前行的起始y坐标
            maxHAscent: hAscent, // 当前行的最大上边距
            maxHDescent: hDescent, // 当前行的最大下边距
        }
    }
    /**
     * 将输入字符转化为行字符，并计算节点宽高
     * @param id 
     * @returns 
     */
    private baseChars2LineChars(id: string) {
        const selectEle = this.getElementById(id);
        if (!selectEle) { return; }
        const { baseChars, x, y } = selectEle;
        if (!baseChars) { return; }
        const startPosX = x;
        const startPosY = y;
        const lineChars: ILineChars[] = [this.generateLineChars()]; // 初始化行字符数组
        let maxHeight = 0; // 当前行的最大高度
        let maxWidth = 0; // 当前行的最大宽度
        let maxHAscent = 0; // 当前行的最大上边距
        let maxHDescent = 0; // 当前行的最大下边距
        for (const c of baseChars) {
            const zFontSize = this.diffFontSize + c.fontSize;
            const cm = this.measureSize(c.c, gFont(zFontSize, c.fontFamily)); // 测量字符的宽度和高度
            const isLineBreak = c.c === LINE_BREAKS; // 是否是换行符
            const char: IChar = {
                c: isLineBreak ? LINE_BREAKS_RENDER : c.c,
                x: 0,
                y: 0,
                ry: 0,
                w: isLineBreak ? 0 : cm.width,
                hAscent: cm.hAscent,
                hDescent: cm.hDescent,
                fontSize: zFontSize,
                fontFamily: c.fontFamily,
                color: c.color,
            };
            maxHeight = Math.max(maxHeight, char.hAscent + char.hDescent);
            maxHAscent = Math.max(maxHAscent, char.hAscent);
            maxHDescent = Math.max(maxHDescent, char.hDescent);

            const currentLineCharNo = lineChars.length - 1; // 当前行字符的索引
            lineChars[currentLineCharNo].chars.push(char);
            lineChars[currentLineCharNo].h = maxHeight; // 当前行最大高度
            lineChars[currentLineCharNo].maxHAscent = maxHAscent; // 当前行最大上边距
            lineChars[currentLineCharNo].maxHDescent = maxHDescent; //
            lineChars[currentLineCharNo].w += char.w;
            if (lineChars[currentLineCharNo].w > maxWidth) {
                maxWidth = lineChars[currentLineCharNo].w;
            }
            if (c.c === LINE_BREAKS) {
                // 换行符，开始新的一行
                lineChars.push(this.generateLineChars());
                maxHeight = 0; // 重置当前行的最大高度
                maxHAscent = 0; // 重置当前行的最大上边距
                maxHDescent = 0; // 重置当前行的最大下边距
            }
        }
        // 计算每行及字符的x和y坐标
        const selectEleWidth = Math.max(maxWidth + 2 * this.LR_PADDING, this.DEFAULT_RECT_MIN_WIDTH); // 行实际最大宽度
        const lengthLineChars = lineChars.length;
        let lineTotalHeight = 0; // 当前行的总高度
        const tbPadding = this.TB_PADDING;
        for (let i = 0; i < lengthLineChars; i++) {
            const line = lineChars[i];
            // line.x = x + LR_PADDING ; // 行的x坐标，左对齐
            line.x = startPosX + (selectEleWidth - line.w) / 2; // 行的x坐标，文字居中
            line.y = startPosY + tbPadding + lineTotalHeight;
            for (let i = 0; i < line.chars.length; i++) {
                const char = line.chars[i];
                const prevChar = line.chars[i - 1];
                char.x = i === 0 ? line.x : (prevChar.x + prevChar.w); // 当前字符的x坐标
                char.ry = line.y; // 当前字符的y坐标，基线对齐
                char.y = line.y + line.maxHAscent; // 字符的实际y坐标，基线对齐
            }
            lineTotalHeight += line.h; // 累加当前行的高度
        }
        selectEle.lineChars = lineChars;
        selectEle.w = selectEleWidth; // 设置元素的宽度
        selectEle.h = lineTotalHeight + 2 * tbPadding; // 设置元素高度
    }
    /**
     * 缩放数据
     */
    private zoomDatas(prevZoom: number, currZoom: number, currOffsetX: number, currOffsetY: number) {
        for (const k in this.dataObject) {
            const item = this.getElementById(k);
            if (!item) { continue; }
            item.x = (item.x / prevZoom - currOffsetX) * currZoom;
            item.y = (item.y / prevZoom - currOffsetY) * currZoom;
            this.baseChars2LineChars(k);
        }
    }
    /**
     * 根据xy确定当前hoverID
     * @param x 
     * @param y 
     * @returns 
     */
    private setHoverElementId(x: number, y: number) {
        const visibleElements = this.visibleElements();
        const ele = visibleElements.find(ele => {
            return x >= ele.x && x <= ele.x + ele.w && y >= ele.y && y <= ele.y + ele.h;
        });
        const hoverEleId = ele && ele.id || ''; // 获取悬停元素的ID
        hoverEleId ? this.setCursor('pointer') : this.setCursor('default');
        if (this._hoverEleId !== hoverEleId) {
            this._hoverEleId = hoverEleId; // 更新悬停元素ID
        }
    }
    /**
     * 根据箭头切换当前选择节点
     * @param arrow 
     * @returns 
     */
    private changeSelectEleIdByArrow(arrow: TArrowKey) {
        if (!this._selectEleId) { return; }
        const selectEle = this.getElementById(this._selectEleId);
        if (!selectEle) { return; }
        if (arrow === ARROW_RIGHT) {
            if (selectEle.children.ids.length <= 0) { return; }
            this._selectEleId = selectEle.children.ids[0]; // 选择第一个子元素
        } else if (arrow === ARROW_LEFT) {
            if (!selectEle.parentId) { return; }
            this._selectEleId = selectEle.parentId; // 选择父元素
        } else if (arrow === ARROW_DOWN || arrow === ARROW_UP) {
            const parentEle = this.getElementById(selectEle.parentId);
            if (!parentEle || parentEle.children.ids.length <= 0) { return; }
            const currentIndex = parentEle.children.ids.indexOf(this._selectEleId);
            if (arrow === ARROW_DOWN) {
                if (currentIndex + 1 >= parentEle.children.ids.length) { return; }
                this._selectEleId = parentEle.children.ids[currentIndex + 1];
            } else {
                if (currentIndex - 1 < 0) { return; }
                this._selectEleId = parentEle.children.ids[currentIndex - 1];
            }
        }
    }
    /**
     * 计算文本选中范围
     * @returns 若有变化则返回true
     */
    private calculateCursorTextSelect(x: number, y: number) {
        if (this._pressInfo.state && this._cursor.h && this._pressInfo.state) {
            const prevRenderStartIndex = this._cursor.renderStartIndex, prevRenderEndIndex = this._cursor.renderEndIndex;
            // this._cursor.renderStartIndex = -1;
            // this._cursor.renderEndIndex = -1;
            const moveCursorPos = this.moveCursorByPos(x, y);
            this._cursor.endIndex = moveCursorPos.index;
            this._cursor.endLocation = moveCursorPos.location;
            const { startIndex, endIndex, endLocation } = this._cursor;
            if (startIndex >= 0 && endIndex >= 0) {
                const ele = this.getElementById(this._selectEleId);
                if (ele) {
                    let start = startIndex, end = endIndex;
                    if (startIndex > endIndex) {
                        start = endIndex - ((endLocation === 'after' && ele.baseChars[endIndex - 1] && ele.baseChars[endIndex - 1].c !== LINE_BREAKS) ? 1 : 0);
                        end = startIndex;
                    } else if (startIndex < endIndex) {
                        start = startIndex;
                        end = endIndex - (endLocation === 'after' ? 1 : 0) + 1;
                        if (!ele.baseChars[end]) {
                            end--;
                        }
                    }
                    let sState = false;
                    let eState = false;
                    if (start !== end) {
                        sState = this._cursor.renderStartIndex === start;
                        eState = this._cursor.renderEndIndex === end;
                        this._cursor.renderStartIndex = start;
                        this._cursor.renderEndIndex = end;
                    }

                    let str = '';
                    for (let i = start; i < end; i++) {
                        str += ele.baseChars[i].c;
                    }
                    // const r = this._cursor.renderStartIndex !== prevRenderStartIndex ||
                    //     this._cursor.renderEndIndex !== prevRenderEndIndex;

                    console.log('STR', str, this._cursor.renderStartIndex, prevRenderStartIndex,
                        this._cursor.renderEndIndex, prevRenderEndIndex
                    );
                    return sState || eState;
                }
            }
        }
        return false;
    }
}